//
// RS Game Framework
// Copyright © 2009 Jedd Haberstro
// jhaberstro@gmail.com
// 
// $Id:
//

#ifndef RS_REFLECTION_ATTRIBUTEPROPERTIES_HPP
#define RS_REFLECTION_ATTRIBUTEPROPERTIES_HPP

#include "rs/Assert.hpp"
#include "rs/Portability.hpp"
#include "rs/ReferenceCounted.hpp"
#include "rs/SmartPointer.hpp"
#include <algorithm>
#include <map>
#include <cstring>

namespace rs
{
    namespace reflection
    {
        class MetaData : public ReferenceCounted
        {
        public:
            
            virtual ~MetaData() {
            }
        };
        
        class AttributeProperties
        {
        public:
            
            typedef SmartPointer< MetaData const > MetaDataPointerType;
            
        private:
            
            typedef std::map< Char8 const*, MetaDataPointerType > MetaDataContainerType;
            
        public:

            static AttributeProperties FriendlyName(Char8 const* friendlyName);

            static AttributeProperties Description(Char8 const* description);

            static AttributeProperties Custom(Char8 const* key, MetaData const* data);

            AttributeProperties();

            AttributeProperties(Char8 const* friendlyName, Char8 const* description);
            
            AttributeProperties(Char8 const* key, MetaData const* data);
                        
            Boolean IsNull() const;
            
            Char8 const* GetFriendlyName() const;
            
            Char8 const* GetDescription() const;
            
            MetaDataPointerType GetMetaData(Char8 const* key) const;
            
            friend AttributeProperties operator+(AttributeProperties const& lhs, AttributeProperties const& rhs);

            friend Boolean operator==(AttributeProperties const& lhs, AttributeProperties const& rhs);

        private:
            
            MetaDataContainerType metaData_;
            Char8 const* friendlyName_;
            Char8 const* description_;
        };
        
        
        inline AttributeProperties AttributeProperties::FriendlyName(Char8 const* friendlyName) {
            AttributeProperties result;
            result.friendlyName_ = friendlyName;
            return result;
        }

        inline AttributeProperties AttributeProperties::Description(Char8 const* description) {
            AttributeProperties result;
            result.description_ = description;
            return result;
        }

        inline AttributeProperties AttributeProperties::Custom(Char8 const* key, MetaData const* data) {
            return AttributeProperties(key, data);
        }
        
        
        inline AttributeProperties::AttributeProperties()
        : friendlyName_(0),
          description_(0) {
        }

        inline AttributeProperties::AttributeProperties(Char8 const* friendlyName, Char8 const* description)
        : friendlyName_(friendlyName),
          description_(description) {
        }
        
        inline AttributeProperties::AttributeProperties(Char8 const* key, MetaData const* data)
        : friendlyName_(0),
          description_(0) {
            RS_ASSERT(key != 0, "key is null");
            metaData_[key] = MetaDataPointerType(data);
        }
        
        inline Boolean AttributeProperties::IsNull() const {
            return friendlyName_ == 0 && description_ == 0 && metaData_.size() == 0;
        }
        
        inline Char8 const* AttributeProperties::GetFriendlyName() const {
            return friendlyName_;
        }
        
        inline Char8 const* AttributeProperties::GetDescription() const {
            return description_;
        }
        
        inline AttributeProperties::MetaDataPointerType AttributeProperties::GetMetaData(Char8 const* key) const {
            RS_ASSERT(key != 0, "key is null");
            RS_ASSERTF(metaData_.find(key) != metaData_.end(), "Attribute property contains no entry for key: '%s'", key);
            return metaData_.find(key)->second;
        }
        
        inline Boolean operator==(AttributeProperties const& lhs, AttributeProperties const& rhs) {
            return (std::strcmp(lhs.GetFriendlyName(), rhs.GetFriendlyName()) == 0 && std::strcmp(lhs.GetDescription(), rhs.GetDescription()) == 0 && lhs.metaData_ == rhs.metaData_);
        }
    }
}


#endif // RS_REFLECTION_ATTRIBUTEPROPERTIES_HPP
